fix(streams): enforce sender ownership on createStream (#809)#967
Conversation
f647c82 to
f67e5da
Compare
|
heads up: main's ci was broken (the Backend CI and Backend Docker Image CI jobs) until the fixes in #969 and #974 just landed, so the red backend/docker checks on this pr are almost certainly stale, they ran against the broken main. please rebase to re-test against the now-green main: |
f67e5da to
b1f3f2e
Compare
createStream never read req.user, so any authenticated wallet could POST an arbitrary sender or flip another owner's cancelled stream back to active via the upsert update branch (keyed only on client-supplied streamId). - 401 when unauthenticated; 403 when JWT subject != body sender - validate sender/recipient/tokenAddress before any DB write - reject (403) upsert against a streamId already owned by another wallet, so the update branch can never reactivate someone else's stream - add controller tests covering non-owner reactivation and field validation
b1f3f2e to
1193203
Compare
|
@ogazboiz Rebased onto the latest main — all checks are green now. Ready for your review. |
ogazboiz
left a comment
There was a problem hiding this comment.
security-sound, and i verified the guard end to end: 401 if unauthenticated, 403 if sender != caller, and a pre-upsert findUnique that 403s if an existing stream's sender != caller, which blocks the reactivate/overwrite-someone-else's-stream hijack, the upsert update branch is only reachable by the proven owner. tests cover 401 / 403 (wrong sender) / 400 (missing sender) + the cancelled-stream-hijack case. merging. (minor, consistent with existing behavior: recipient/tokenAddress are validated non-empty but not as full Stellar addresses.)
Fixes #809
Problem
createStreamwiredrequireAuthbut never readreq.user. It calledprisma.stream.upsertkeyed only on the client-suppliedstreamId, whose update branch set{ isActive: true }. So any logged-in wallet could:{ streamId: <someone else's cancelled stream>, ... }and flipisActiveback totrue(the body's sender/recipient are ignored on update), andsenderit does not own.Fix
401when unauthenticated and403when the JWT subject (req.user.publicKey) is not the bodysender.sender/recipient/tokenAddressbefore any DB write.403if it is owned by another wallet, so the update branch can never reactivate or overwrite someone else's stream.Tests
Added controller tests covering: unauthenticated (401), caller≠sender (403), missing sender (400), and a non-owner attempting to reactivate a victim's cancelled stream (403, no DB write). All
stream.controller.test.tstests pass.Acceptance criteria
createStreamrejects (403) whenreq.user.publicKeyis not the body senderisActive:truefor an existing stream owned by someone elsePOST /v1/streamssender/recipient/tokenAddressvalidated before any DB write